/*****************************************************************************/
/*  gtkui.c - GTK+ UI related functions for gFTP                             */
/*  Copyright (C) 1998-2007 Brian Masney <masneyb@gftp.org>                  */
/*                                                                           */
/*  This program is free software; you can redistribute it and/or modify     */
/*  it under the terms of the GNU General Public License as published by     */
/*  the Free Software Foundation; either version 2 of the License, or        */
/*  (at your option) any later version.                                      */
/*                                                                           */
/*  This program is distributed in the hope that it will be useful,          */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
/*  GNU General Public License for more details.                             */
/*                                                                           */
/*  You should have received a copy of the GNU General Public License        */
/*  along with this program; if not, write to the Free Software              */
/*  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA      */
/*****************************************************************************/

#include "gftp-gtk.h"
static const char cvsid[] = "$Id: gtkui.c 932 2007-05-19 01:37:07Z masneyb $";


void
gftpui_lookup_file_colors( gftp_file * fle, char **start_color,
                           char ** end_color ) {
  *start_color = GFTPUI_COMMON_COLOR_NONE;
  *end_color = GFTPUI_COMMON_COLOR_NONE;
}


void
gftpui_run_command( GtkWidget * widget, gpointer data ) {
  const char *txt;
  txt = gtk_entry_get_text( GTK_ENTRY( gftpui_command_widget ) );
  gftpui_common_process_command( &window1, window1.request,
                                 &window2, window2.request, txt );
  gtk_entry_set_text( GTK_ENTRY( gftpui_command_widget ), "" );
}


void
gftpui_refresh( void *uidata, int clear_cache_entry ) {
  gftp_window_data * wdata;
  wdata = uidata;
  wdata->request->refreshing = 1;
  if( !check_status( _( "Refresh" ), wdata, 0, 0, 0, 1 ) ) {
    wdata->request->refreshing = 0;
    return;
  }
  if( clear_cache_entry ) {
    gftp_delete_cache_entry( wdata->request, NULL, 0 );
  }
  if( check_reconnect( wdata ) < 0 ) {
    wdata->request->refreshing = 0;
    return;
  }
  gtk_clist_freeze( GTK_CLIST( wdata->listbox ) );
  remove_files_window( wdata );
  ftp_list_files( wdata );
  gtk_clist_thaw( GTK_CLIST( wdata->listbox ) );
  wdata->request->refreshing = 0;
}


#define _GFTPUI_GTK_USER_PW_SIZE  256

static void
_gftpui_gtk_set_username( gftp_request * request, gftp_dialog_data * ddata ) {
  gftp_set_username( request, gtk_entry_get_text( GTK_ENTRY( ddata->edit ) ) );
  request->stopable = 0;
}


static void
_gftpui_gtk_set_password( gftp_request * request, gftp_dialog_data * ddata ) {
  gftp_set_password( request, gtk_entry_get_text( GTK_ENTRY( ddata->edit ) ) );
  request->stopable = 0;
}


static void
_gftpui_gtk_abort( gftp_request * request, gftp_dialog_data * ddata ) {
  request->stopable = 0;
}

void
gftpui_show_busy( gboolean busy ) {
  GtkWidget * toplevel = gtk_widget_get_toplevel( openurl_btn );
  GdkDisplay * display = gtk_widget_get_display( toplevel );
  GdkCursor * busyCursor =
    ( busy ) ? ( gdk_cursor_new_for_display( display, GDK_WATCH ) ) : NULL;
  gdk_window_set_cursor( toplevel->window, busyCursor );
  if( busy ) {
    gdk_cursor_unref( busyCursor );
  }
}

void
gftpui_prompt_username( void *uidata, gftp_request * request ) {
  MakeEditDialog( _( "Enter Username" ),
                  _( "Please enter your username for this site" ), NULL,
                  1, NULL, gftp_dialog_button_connect,
                  _gftpui_gtk_set_username, request,
                  _gftpui_gtk_abort, request );
  request->stopable = 1;
  while( request->stopable ) {
    GDK_THREADS_LEAVE();
    #if GTK_MAJOR_VERSION == 1
    g_main_iteration( TRUE );
    #else
    g_main_context_iteration( NULL, TRUE );
    #endif
  }
}


void
gftpui_prompt_password( void *uidata, gftp_request * request ) {
  MakeEditDialog( _( "Enter Password" ),
                  _( "Please enter your password for this site" ), NULL,
                  0, NULL, gftp_dialog_button_connect,
                  _gftpui_gtk_set_password, request,
                  _gftpui_gtk_abort, request );
  request->stopable = 1;
  while( request->stopable ) {
    GDK_THREADS_LEAVE();
    #if GTK_MAJOR_VERSION == 1
    g_main_iteration( TRUE );
    #else
    g_main_context_iteration( NULL, TRUE );
    #endif
  }
}


/* The wakeup main thread functions are so that after the thread terminates
   there won't be a delay in updating the GUI */
static void
_gftpui_wakeup_main_thread( gpointer data, gint source,
                            GdkInputCondition condition ) {
  gftp_request * request;
  char c;
  request = data;
  if( request->wakeup_main_thread[0] > 0 ) {
    read( request->wakeup_main_thread[0], &c, 1 );
  }
}


static gint
_gftpui_setup_wakeup_main_thread( gftp_request * request ) {
  gint handler;
  if( socketpair( AF_UNIX, SOCK_STREAM, 0, request->wakeup_main_thread ) == 0 ) {
    handler = gdk_input_add( request->wakeup_main_thread[0],
                             GDK_INPUT_READ, _gftpui_wakeup_main_thread,
                             request );
  } else {
    request->wakeup_main_thread[0] = 0;
    request->wakeup_main_thread[1] = 0;
    handler = 0;
  }
  return ( handler );
}


static void
_gftpui_teardown_wakeup_main_thread( gftp_request * request, gint handler ) {
  if( request->wakeup_main_thread[0] > 0 && request->wakeup_main_thread[1] > 0 ) {
    gdk_input_remove( handler );
    close( request->wakeup_main_thread[0] );
    close( request->wakeup_main_thread[1] );
    request->wakeup_main_thread[0] = 0;
    request->wakeup_main_thread[1] = 0;
  }
}

static void *
_gftpui_gtk_thread_func( void *data ) {
  gftpui_gtk_thread_data * thread_data;
  void *ret;
  thread_data = data;
  ret = thread_data->func( thread_data->cdata );
  if( thread_data->cdata->request->wakeup_main_thread[1] > 0 ) {
    write( thread_data->cdata->request->wakeup_main_thread[1], " ", 1 );
  }
  return ( ret );
}


void *
gftpui_generic_thread( void * ( *func )( void * ), void *data ) {
  gftpui_gtk_thread_data * thread_data;
  gftpui_callback_data * cdata;
  gftp_window_data * wdata;
  gint handler;
  void * ret;
  cdata = data;
  wdata = cdata->uidata;
  wdata->request->stopable = 1;
  gtk_widget_set_sensitive( stop_btn, 1 );
  thread_data = g_malloc0( sizeof( *thread_data ) );
  thread_data->func = func;
  thread_data->cdata = cdata;
  handler = _gftpui_setup_wakeup_main_thread( cdata->request );
  pthread_create( &wdata->tid, NULL, _gftpui_gtk_thread_func, thread_data );
  while( wdata->request->stopable ) {
    GDK_THREADS_LEAVE();
    #if GTK_MAJOR_VERSION == 1
    g_main_iteration( TRUE );
    #else
    g_main_context_iteration( NULL, TRUE );
    #endif
  }
  _gftpui_teardown_wakeup_main_thread( cdata->request, handler );
  g_free( thread_data );
  pthread_join( wdata->tid, &ret );
  gtk_widget_set_sensitive( stop_btn, 0 );
  if( !GFTP_IS_CONNECTED( wdata->request ) ) {
    gftpui_disconnect( wdata );
  }
  return ( ret );
}


int
gftpui_check_reconnect( gftpui_callback_data * cdata ) {
  gftp_window_data * wdata;
  wdata = cdata->uidata;
  return ( wdata->request->cached && wdata->request->datafd < 0 &&
           !wdata->request->always_connected &&
           !ftp_connect( wdata, wdata->request ) ? -1 : 0 );
}


void
gftpui_run_function_callback( gftp_window_data * wdata,
                              gftp_dialog_data * ddata ) {
  gftpui_callback_data * cdata;
  const char *edttext;
  cdata = ddata->yespointer;
  if( ddata->edit != NULL ) {
    edttext = gtk_entry_get_text( GTK_ENTRY( ddata->edit ) );
    if( *edttext == '\0' ) {
      ftp_log( gftp_logging_error, NULL,
               _( "Operation canceled...you must enter a string\n" ) );
      return;
    }
    cdata->input_string = g_strdup( edttext );
  }
  if( ddata->checkbox != NULL ) {
    cdata->toggled = GTK_TOGGLE_BUTTON( ddata->checkbox )->active;
  } else {
    cdata->toggled = 0;
  }
  gtk_widget_destroy( ddata->dialog );
  ddata->dialog = NULL;
  gftpui_common_run_callback_function( cdata );
}


void
gftpui_run_function_cancel_callback( gftp_window_data * wdata,
                                     gftp_dialog_data * ddata ) {
  gftpui_callback_data * cdata;
  cdata = ddata->yespointer;
  if( cdata->input_string != NULL ) {
    g_free( cdata->input_string );
  }
  if( cdata->source_string != NULL ) {
    g_free( cdata->source_string );
  }
  g_free( cdata );
}


void
gftpui_mkdir_dialog( gpointer data ) {
  gftpui_callback_data * cdata;
  gftp_window_data * wdata;
  wdata = data;
  cdata = g_malloc0( sizeof( *cdata ) );
  cdata->request = wdata->request;
  cdata->uidata = wdata;
  cdata->run_function = gftpui_common_run_mkdir;
  if( !check_status( _( "Mkdir" ), wdata, gftpui_common_use_threads( wdata->request ), 0, 0, wdata->request->mkdir != NULL ) ) {
    return;
  }
  MakeEditDialog( _( "Make Directory" ), _( "Enter name of directory to create" ),
                  NULL, 1, NULL, gftp_dialog_button_create,
                  gftpui_run_function_callback, cdata,
                  gftpui_run_function_cancel_callback, cdata );
}


void
gftpui_rename_dialog( gpointer data ) {
  gftpui_callback_data * cdata;
  GList *templist, *filelist;
  gftp_window_data * wdata;
  gftp_file * curfle;
  char *tempstr;
  int num;
  wdata = data;
  cdata = g_malloc0( sizeof( *cdata ) );
  cdata->request = wdata->request;
  cdata->uidata = wdata;
  cdata->run_function = gftpui_common_run_rename;
  if( !check_status( _( "Rename" ), wdata, gftpui_common_use_threads( wdata->request ), 1, 1, wdata->request->rename != NULL ) ) {
    return;
  }
  templist = gftp_gtk_get_list_selection( wdata );
  num = 0;
  filelist = wdata->files;
  templist = get_next_selection( templist, &filelist, &num );
  curfle = filelist->data;
  cdata->source_string = g_strdup( curfle->file );
  tempstr = g_strdup_printf( _( "What would you like to rename %s to?" ),
                             cdata->source_string );
  MakeEditDialog( _( "Rename" ), tempstr, cdata->source_string, 1, NULL,
                  gftp_dialog_button_rename,
                  gftpui_run_function_callback, cdata,
                  gftpui_run_function_cancel_callback, cdata );
  g_free( tempstr );
}


void
gftpui_site_dialog( gpointer data ) {
  gftpui_callback_data * cdata;
  gftp_window_data * wdata;
  wdata = data;
  cdata = g_malloc0( sizeof( *cdata ) );
  cdata->request = wdata->request;
  cdata->uidata = wdata;
  cdata->run_function = gftpui_common_run_site;
  if( !check_status( _( "Site" ), wdata, 0, 0, 0, wdata->request->site != NULL ) ) {
    return;
  }
  MakeEditDialog( _( "Site" ), _( "Enter site-specific command" ), NULL, 1,
                  _( "Prepend with SITE" ), gftp_dialog_button_ok,
                  gftpui_run_function_callback, cdata,
                  gftpui_run_function_cancel_callback, cdata );
}


int
gftpui_run_chdir( gpointer uidata, char *directory ) {
  gftpui_callback_data * cdata;
  gftp_window_data * wdata;
  char *tempstr;
  int ret;
  wdata = uidata;
  if( ( tempstr = gftp_expand_path( wdata->request, directory ) ) == NULL ) {
    return ( FALSE );
  }
  cdata = g_malloc0( sizeof( *cdata ) );
  cdata->request = wdata->request;
  cdata->uidata = wdata;
  cdata->run_function = gftpui_common_run_chdir;
  cdata->input_string = tempstr;
  cdata->dont_clear_cache = 1;
  ret = gftpui_common_run_callback_function( cdata );
  g_free( tempstr );
  g_free( cdata );
  return ( ret );
}


void
gftpui_chdir_dialog( gpointer data ) {
  GList *templist, *filelist;
  gftp_window_data * wdata;
  gftp_file * curfle;
  char *tempstr;
  int num;
  wdata = data;
  if( !check_status( _( "Chdir" ), wdata, gftpui_common_use_threads( wdata->request ), 1, 0,
                     wdata->request->chdir != NULL ) ) {
    return;
  }
  templist = gftp_gtk_get_list_selection( wdata );
  num = 0;
  filelist = wdata->files;
  templist = get_next_selection( templist, &filelist, &num );
  curfle = filelist->data;
  tempstr = gftp_build_path( wdata->request, wdata->request->directory,
                             curfle->file, NULL );
  gftpui_run_chdir( wdata, tempstr );
  g_free( tempstr );
}


void
gftpui_disconnect( void *uidata ) {
  gftp_window_data * wdata;
  wdata = uidata;
  gftp_delete_cache_entry( wdata->request, NULL, 1 );
  gftp_disconnect( wdata->request );
  remove_files_window( wdata );
  /* Free the request structure so that all old settings are purged. */
  gftp_request_destroy( wdata->request, 0 );
  gftp_gtk_init_request( wdata );
  update_window_info();
}


char *
gftpui_gtk_get_utf8_file_pos( gftp_file * fle ) {
  char *pos;
  if( ( pos = strrchr( fle->file, '/' ) ) != NULL ) {
    pos++;
  } else {
    pos = fle->file;
  }
  return ( pos );
}


static void
_protocol_yes_answer( gpointer answer, gftp_dialog_data * ddata ) {
  *( int * ) answer = 1;
}


static void
_protocol_no_answer( gpointer answer, gftp_dialog_data * ddata ) {
  *( int * ) answer = 0;
}


int
gftpui_protocol_ask_yes_no( gftp_request * request, char *title,
                            char *question ) {
  int answer = -1;
  GDK_THREADS_ENTER();
  MakeYesNoDialog( title, question, _protocol_yes_answer, &answer,
                   _protocol_no_answer, &answer );
  if( gftp_protocols[request->protonum].use_threads ) {
    /* Let the main loop in the main thread run the events */
    GDK_THREADS_LEAVE();
    while( answer == -1 ) {
      sleep( 1 );
    }
  } else {
    while( answer == -1 ) {
      GDK_THREADS_LEAVE();
      #if GTK_MAJOR_VERSION == 1
      g_main_iteration( TRUE );
      #else
      g_main_context_iteration( NULL, TRUE );
      #endif
    }
  }
  return ( answer );
}


static void
_protocol_ok_answer( char *buf, gftp_dialog_data * ddata ) {
  buf[1] = ' '; /* In case this is an empty string entered */
  strncpy( buf, gtk_entry_get_text( GTK_ENTRY( ddata->edit ) ), BUFSIZ );
}


static void
_protocol_cancel_answer( char *buf, gftp_dialog_data * ddata ) {
  buf[0] = '\0';
  buf[1] = '\0';
}


char *
gftpui_protocol_ask_user_input( gftp_request * request, char *title,
                                char *question, int shown ) {
  char buf[BUFSIZ];
  GDK_THREADS_ENTER();
  *buf = '\0';
  *( buf + 1 ) = ' ';
  MakeEditDialog( title, question, NULL, shown, NULL, gftp_dialog_button_ok,
                  _protocol_ok_answer, &buf, _protocol_cancel_answer, &buf );
  if( gftp_protocols[request->protonum].use_threads ) {
    /* Let the main loop in the main thread run the events */
    GDK_THREADS_LEAVE();
    while( *buf == '\0' && *( buf + 1 ) == ' ' ) {
      sleep( 1 );
    }
  } else {
    while( *buf == '\0' && *( buf + 1 ) == ' ' ) {
      GDK_THREADS_LEAVE();
      #if GTK_MAJOR_VERSION == 1
      g_main_iteration( TRUE );
      #else
      g_main_context_iteration( NULL, TRUE );
      #endif
    }
  }
  if( *buf != '\0' ) {
    return ( g_strdup( buf ) );
  } else {
    return ( NULL );
  }
}

